# 一、前言
这个周末,注意力都在学习基础Js知识上面,刚好看到了闭包这个神圣的东西,所以打算把这两天学到的总结下来,算是巩固自己所学。也可能有些不正确的地方,也请大家看到了,麻烦在评论下提醒一下,算是互相学习了。
二、什么是闭包?
百度百科定义:闭包就是能够读取其他函数内部变量的函数。
在解释之前,得先讲讲作用域。先来看下面这个示例:
var a = 1;
function f(){
var b = 2;
console.log(a) // 1
}
console.log(b) // undefined
示例中包含了两种作用域,一种是属于全局的全局作用域,另一种是属于函数f
的局部作用域。由于Javascript
这种链式作用域(父作用域是可以被其子作用域访问的,而子作用域却不能被父作用域访问)的机制,使得示例最后一行输出了undefined
从此可以看出,无法从父作用域中访问子作用域。而我们再来看闭包的定义:闭包就是能够读取其他函数内部变量的函数。也就是闭包可以让我们从父作用域中访问到子作用域,具体怎么实现的呢?来看这个经典的例子:
function foo(){
var a = 2;
function bar(){
console.log(a);
}
return bar;
}
var baz = foo();
baz(); // 2 -> 这就是闭包的效果
这个示例中,闭包就是函数bar
。可以看到,我们通过在函数foo
内部定义其子函数bar
,并将其作为foo
返回值,因为bar
函数作用域可以访问foo
的作用域,所以实现了从全局作用域访问foo
函数作用域的效果。
三、闭包的应用
其实,平时你所写的代码中,早就用到了闭包,只是你还没发现而已。
本质上,无论何时何地,如果将函数当作值传递到其他地方使用(非函数所在作用域),你就已经使用了闭包。例如上面示例说的函数bar
,我们将他传递到了全局作用域下,通过这种方式访问到本该不能访问的变量a
。
在定时器、事件监听器、Ajax请求、任何其他异步(或同步)任务中,只要使用了回调函数,实际上就是在使用闭包!
四、注意事项
闭包会让他所在作用域中的变量始终保存在内存中,而不会被垃圾回收机制回收。
function foo(p){
function bar(){
console.log(++p);
}
return bar;
}
var baz = foo(1);
baz(); // 2
baz(); // 3
baz(); // 4
var bazz = foo(2);
bazz(); // 3
bazz(); // 4
bazz(); // 5
baz(); // 5
看到了没,闭包的使用,函数调用之后,让其外层函数的内部变量(foo
函数内的变量)始终保存在了内存中,而不会被回收。
值得注意的是,每次调用一次foo
,都会生成一个新的闭包,都会在内存中保存下其外层函数的内部变量。因此要注意闭包的使用,否则会导致性能问题。
五、总结
闭包的作用:
- 能够读取其他函数内部变量。
- 让其他函数的内部变量始终保存在内存中。
参考:
附:你不知道的Javascript系列电子书网盘链接, 密码:i8jf
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。